﻿/*
 * @author Lee 
 * Time: 20180403 
 * Abstract: SharePoint API的二次封装
 */

using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.WebParts;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;

namespace SharePointHelper.DLL.CSOM
{
    public class Lists
    {
        #region 获取一个list的根文件夹名称
        /// <summary>
        /// 获取一个list的根文件夹名称
        /// </summary>
        /// <param name="siteURL"></param>
        /// <param name="listTitle"></param>
        /// <returns></returns>
        public static string getRootFolderNameOfList(string siteURL, string listTitle)
        {
            ClientContext context = new ClientContext(siteURL);
            List list = context.Web.Lists.GetByTitle(listTitle);
            Folder rootFolder = list.RootFolder;
            context.Load(list);
            context.Load(rootFolder);
            context.ExecuteQuery();
            return list.RootFolder.Name;
        }

        public static string getRootFolderNameOfList(ClientContext context, string listTitle)
        {
            List list = context.Web.Lists.GetByTitle(listTitle);
            Folder rootFolder = list.RootFolder;
            context.Load(list);
            context.Load(rootFolder);
            context.ExecuteQuery();
            return list.RootFolder.Name;

        }
        #endregion

        #region 获取改变的数据
        /// <summary>
        /// 获取改变的数据
        /// </summary>
        /// <param name="siteURL"></param>
        /// <returns></returns>
        public static ChangeCollection getChangedData(string siteURL)
        {
            ClientContext context = new ClientContext(siteURL);
            Web web = context.Web;
            context.Load(web);
            ChangeQuery siteCQ = new ChangeQuery(true, true);
            siteCQ.DeleteObject = true;
            siteCQ.Update = false;
            siteCQ.Add = false;
            siteCQ.SystemUpdate = false;
            siteCQ.Item = false;
            siteCQ.Web = false;
            siteCQ.RoleAssignmentAdd = false;
            siteCQ.RoleAssignmentDelete = false;
            siteCQ.GroupMembershipAdd = false;
            siteCQ.View = false;
            siteCQ.RoleDefinitionAdd = false;

            ChangeCollection webChanges = web.GetChanges(siteCQ);
            context.Load(webChanges);
            context.ExecuteQuery();
            return webChanges;
        }

        public static ChangeCollection getChangedData(ClientContext context)
        {
            Web web = context.Web;
            context.Load(web);
            ChangeQuery siteCQ = new ChangeQuery(true, true);
            siteCQ.DeleteObject = true;
            siteCQ.Update = false;
            siteCQ.Add = false;
            siteCQ.SystemUpdate = false;
            siteCQ.Item = false;
            siteCQ.Web = false;
            siteCQ.RoleAssignmentAdd = false;
            siteCQ.RoleAssignmentDelete = false;
            siteCQ.GroupMembershipAdd = false;
            siteCQ.View = false;
            siteCQ.RoleDefinitionAdd = false;

            ChangeCollection webChanges = web.GetChanges(siteCQ);
            context.Load(webChanges);
            context.ExecuteQuery();
            return webChanges;
        }
        #endregion

        #region 获取回收站里面的所有item
        /// <summary>
        /// 获取回收站里面的所有item
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static RecycleBinItemCollection getRecycleBinItems(ClientContext context)
        {
            Web web = context.Web;

            // Get all the recycle bin items  
            // Reference: https://msdn.microsoft.com/EN-US/library/microsoft.sharepoint.client.recyclebinitem_members.aspx                 
            RecycleBinItemCollection rbiColl = web.RecycleBin;
            context.Load(rbiColl);

            // Execute the query to the server  
            context.ExecuteQuery();
            return rbiColl;
        }

        public static RecycleBinItemCollection getRecycleBinItems(string siteURL)
        {
            ClientContext context = new ClientContext(siteURL);
            Web web = context.Web;

            // Get all the recycle bin items  
            // Reference: https://msdn.microsoft.com/EN-US/library/microsoft.sharepoint.client.recyclebinitem_members.aspx                 
            RecycleBinItemCollection rbiColl = web.RecycleBin;
            context.Load(rbiColl);

            // Execute the query to the server  
            context.ExecuteQuery();

            return rbiColl;
        }
        #endregion

        #region 给view添加field
        /// <summary>
        /// 给view添加field
        /// </summary>
        /// <param name="clientContext"></param>
        /// <param name="list"></param>
        /// <param name="ViewName"></param>
        /// <param name="FieldName"></param>
        public static void addFieldToView(ClientContext clientContext, List list, string ViewName, string FieldName)
        {

            View v = list.Views.GetByTitle(ViewName);

            // Load it up
            clientContext.Load(v, x => x.ViewFields);
            clientContext.ExecuteQuery();

            // Get the field I want to add to the view
            Field name = list.Fields.GetByInternalNameOrTitle(FieldName);

            clientContext.Load(name);
            clientContext.ExecuteQuery();

            // Add this field to the view !! Nothing else in the view object to allow to make it visible by default !!
            v.ViewFields.Add(name.InternalName);

            // Finally, update the view
            v.Update();
            clientContext.Load(v);
            clientContext.ExecuteQuery();
        }
        #endregion

        #region 通过REST API获取list JSON串
        /// <summary>
        /// 通过REST API获取list JSON串
        /// </summary>
        /// <param name="webUri"></param>
        /// <param name="credentials"></param>
        /// <param name="listTitle"></param>
        /// <returns></returns>
        public static JToken GetList(Uri webUri, ICredentials credentials, string listTitle)
        {
            using (WebClient client = new WebClient())
            {
                client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
                client.Credentials = credentials;
                client.Headers.Add(HttpRequestHeader.ContentType, "application/json;odata=verbose");
                client.Headers.Add(HttpRequestHeader.Accept, "application/json;odata=verbose");
                Uri endpointUri = new Uri(webUri + "/_api/web/lists/getbytitle('" + listTitle + "')");
                string result = client.DownloadString(endpointUri);

                JObject jo = (JObject)JsonConvert.DeserializeObject(result);
                JToken jToken = jo["d"];
                return jToken;
            }
        }
        #endregion

        #region copy Doc中的所有文件到另一个Doc中
        /// <summary>
        /// copy Doc中的所有文件到另一个Doc中
        /// </summary>
        /// <param name="context"></param>
        /// <param name="sourceListName"></param>
        /// <param name="destinationListName"></param>
        public static void CopyDocAllFromOneListToAnother(ClientContext context, string sourceListName, string destinationListName)
        {

            context.Load(context.Web);
            context.ExecuteQuery();
            string siteUrl = context.Web.Url;
            Web web = context.Web;

            string host = null;
            if (siteUrl.Split('/').Length > 3)
            {
                string[] strArr = siteUrl.Split('/');
                for (int x = 0; x < 3; x++)
                {
                    if (x != 2)
                    {
                        host += strArr[x] + "/";
                    }
                    else
                    {
                        host += strArr[x];
                    }
                }
            }
            else
            {
                host = siteUrl;
            }
            List source = web.Lists.GetByTitle(sourceListName);
            List destination = web.Lists.GetByTitle(destinationListName);
            context.Load(source);
            context.Load(destination);
            context.Load(web);
            context.ExecuteQuery();

            FileCollection files = source.RootFolder.Files;
            context.Load(files);
            context.ExecuteQuery();

            foreach (Microsoft.SharePoint.Client.File file in files)
            {
                FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, file.ServerRelativeUrl);
                string filePath = host + file.ServerRelativeUrl;
                System.IO.Stream fileStream = fileInfo.Stream;
                FileCreationInformation createFile = new FileCreationInformation();
                byte[] bufferByte = new byte[1024 * 100];
                System.IO.MemoryStream memory = new System.IO.MemoryStream();
                int len = 0;
                while ((len = fileStream.Read(bufferByte, 0, bufferByte.Length)) > 0)
                {
                    memory.Write(bufferByte, 0, len);
                }
                byte[] bytes = memory.GetBuffer();

                createFile.Content = bytes;
                createFile.Url = siteUrl + "/" + destinationListName + "/" + file.Name;
                createFile.Overwrite = true;
                Microsoft.SharePoint.Client.File newFile = destination.RootFolder.Files.Add(createFile);
                newFile.ListItemAllFields.Update();
                context.ExecuteQuery();

            }
        }
        #endregion

        #region copy Doc中的某个文件到另一个Doc中
        /// <summary>
        /// copy Doc中的某个文件到另一个Doc中
        /// </summary>
        /// <param name="context"></param>
        /// <param name="sourceListName">TestForm</param>
        /// <param name="destinationListName">MyDocLib</param>
        /// <param name="fileName">Test1.xml</param>
        public static void CopyDocFromOneListToAnother(ClientContext context, string sourceListName, string destinationListName, string fileName)
        {
            context.Load(context.Web);
            context.ExecuteQuery();
            string siteUrl = context.Web.Url;
            Web web = context.Web;

            string host = null;
            if (siteUrl.Split('/').Length > 3)
            {
                string[] strArr = siteUrl.Split('/');
                for (int x = 0; x < 3; x++)
                {
                    if (x != 2)
                    {
                        host += strArr[x] + "/";
                    }
                    else
                    {
                        host += strArr[x];
                    }
                }
            }
            else
            {
                host = siteUrl;
            }

            List source = web.Lists.GetByTitle(sourceListName);
            List destination = web.Lists.GetByTitle(destinationListName);
            context.Load(source);
            context.Load(destination);
            context.Load(web);
            context.ExecuteQuery();

            FileCollection files = source.RootFolder.Files;
            Microsoft.SharePoint.Client.File file = files.GetByUrl(siteUrl + "/" + sourceListName + "/" + fileName);
            context.Load(file);
            context.ExecuteQuery();

            FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, file.ServerRelativeUrl);
            string filePath = host + file.ServerRelativeUrl;
            System.IO.Stream fileStream = fileInfo.Stream;
            FileCreationInformation createFile = new FileCreationInformation();
            byte[] bufferByte = new byte[1024 * 100];
            System.IO.MemoryStream memory = new System.IO.MemoryStream();
            int len = 0;
            while ((len = fileStream.Read(bufferByte, 0, bufferByte.Length)) > 0)
            {
                memory.Write(bufferByte, 0, len);
            }
            byte[] bytes = memory.GetBuffer();

            createFile.Content = bytes;
            createFile.Url = siteUrl + "/" + destinationListName + "/" + file.Name;
            createFile.Overwrite = true;
            Microsoft.SharePoint.Client.File newFile = destination.RootFolder.Files.Add(createFile);
            newFile.ListItemAllFields.Update();
            context.ExecuteQuery();

        }
        #endregion

        #region Copy 某个site collection 的 Doc 中的某个文件到另一个site collection 的 Doc中(在同一个Web Application下)
        /// <summary>
        /// Copy 某个site collection 的 Doc 中的某个文件到另一个site collection 的 Doc中
        /// </summary>
        /// <param name="sourceContext"></param>
        /// <param name="destinationContext"></param>
        /// <param name="sourceListName">sourceList</param>
        /// <param name="destinationListName">destinationList</param>
        /// <param name="fileName">/folder/test.txt</param>
        public static void CopyDocFromOneListToAnother(ClientContext sourceContext, ClientContext destinationContext, string sourceListName, string destinationListName, string fileRelativePath)
        {
            Web sourceWeb = sourceContext.Web;
            Web destinationWeb = destinationContext.Web;
            sourceContext.Load(sourceWeb);
            destinationContext.Load(destinationWeb);
            sourceContext.ExecuteQuery();
            destinationContext.ExecuteQuery();

            string sourceSiteUrl = sourceWeb.Url;

            string host = null;
            if (sourceSiteUrl.Split('/').Length > 3)
            {
                string[] strArr = sourceSiteUrl.Split('/');
                for (int x = 0; x < 3; x++)
                {
                    if (x != 2)
                    {
                        host += strArr[x] + "/";
                    }
                    else
                    {
                        host += strArr[x];
                    }
                }
            }
            else
            {
                host = sourceSiteUrl;
            }

            List source = sourceWeb.Lists.GetByTitle(sourceListName);
            List destination = destinationWeb.Lists.GetByTitle(destinationListName);
            sourceContext.Load(source);
            destinationContext.Load(destination);
            sourceContext.Load(sourceWeb);
            sourceContext.ExecuteQuery();
            destinationContext.ExecuteQuery();

            FileCollection files = source.RootFolder.Files;
            Microsoft.SharePoint.Client.File file = files.GetByUrl(sourceSiteUrl + "/" + sourceListName + fileRelativePath);
            sourceContext.Load(file);
            sourceContext.ExecuteQuery();

            FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(sourceContext, file.ServerRelativeUrl);
            string filePath = host + file.ServerRelativeUrl;
            System.IO.Stream fileStream = fileInfo.Stream;
            FileCreationInformation createFile = new FileCreationInformation();
            byte[] bufferByte = new byte[1024 * 100];
            System.IO.MemoryStream memory = new System.IO.MemoryStream();
            int len = 0;
            while ((len = fileStream.Read(bufferByte, 0, bufferByte.Length)) > 0)
            {
                memory.Write(bufferByte, 0, len);
            }
            byte[] bytes = memory.GetBuffer();

            createFile.Content = bytes;
            createFile.Url = sourceSiteUrl + "/" + destinationListName + "/" + file.Name;
            createFile.Overwrite = true;
            Microsoft.SharePoint.Client.File newFile = destination.RootFolder.Files.Add(createFile);
            newFile.ListItemAllFields.Update();
            destinationContext.ExecuteQuery();
        }
        #endregion

        #region Move Doc中的某个文件到另一个Doc中
        /// <summary>
        /// move Doc中的某个文件到另一个Doc中
        /// </summary>
        /// <param name="context"></param>
        /// <param name="sourceListName">TestForm</param>
        /// <param name="destinationListName">MyDocLib</param>
        /// <param name="fileName">Test1.xml</param>
        public static void MoveDocFromOneListToAnother(ClientContext context, string sourceListName, string destinationListName, string fileName)
        {
            context.Load(context.Web);
            context.ExecuteQuery();
            string siteUrl = context.Web.Url;
            Web web = context.Web;

            string host = null;
            if (siteUrl.Split('/').Length > 3)
            {
                string[] strArr = siteUrl.Split('/');
                for (int x = 0; x < 3; x++)
                {
                    if (x != 2)
                    {
                        host += strArr[x] + "/";
                    }
                    else
                    {
                        host += strArr[x];
                    }
                }
            }
            else
            {
                host = siteUrl;
            }

            List source = web.Lists.GetByTitle(sourceListName);
            List destination = web.Lists.GetByTitle(destinationListName);
            context.Load(source);
            context.Load(destination);
            context.Load(web);
            context.ExecuteQuery();

            FileCollection files = source.RootFolder.Files;
            Microsoft.SharePoint.Client.File file = files.GetByUrl(siteUrl + "/" + sourceListName + "/" + fileName);
            context.Load(file);
            context.ExecuteQuery();

            FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, file.ServerRelativeUrl);
            string filePath = host + file.ServerRelativeUrl;
            System.IO.Stream fileStream = fileInfo.Stream;
            FileCreationInformation createFile = new FileCreationInformation();
            byte[] bufferByte = new byte[1024 * 100];
            System.IO.MemoryStream memory = new System.IO.MemoryStream();
            int len = 0;
            while ((len = fileStream.Read(bufferByte, 0, bufferByte.Length)) > 0)
            {
                memory.Write(bufferByte, 0, len);
            }
            byte[] bytes = memory.GetBuffer();

            createFile.Content = bytes;
            createFile.Url = siteUrl + "/" + destinationListName + "/" + file.Name;
            createFile.Overwrite = true;
            Microsoft.SharePoint.Client.File newFile = destination.RootFolder.Files.Add(createFile);
            newFile.ListItemAllFields.Update();
            context.ExecuteQuery();

            ListItem item = file.ListItemAllFields;
            context.Load(item);
            item.DeleteObject();
            context.ExecuteQuery();
        }
        #endregion

        #region Move Doc中的所有文件到另一个Doc中
        /// <summary>
        /// move Doc中的所有文件到另一个Doc中
        /// </summary>
        /// <param name="context"></param>
        /// <param name="sourceListName"></param>
        /// <param name="destinationListName"></param>
        public static void MoveAllDocsFromOneListToAnother(ClientContext context, string sourceListName, string destinationListName)
        {

            context.Load(context.Web);
            context.ExecuteQuery();
            string siteUrl = context.Web.Url;
            Web web = context.Web;

            string host = null;
            if (siteUrl.Split('/').Length > 3)
            {
                string[] strArr = siteUrl.Split('/');
                for (int x = 0; x < 3; x++)
                {
                    if (x != 2)
                    {
                        host += strArr[x] + "/";
                    }
                    else
                    {
                        host += strArr[x];
                    }
                }
            }
            else
            {
                host = siteUrl;
            }

            List source = web.Lists.GetByTitle(sourceListName);
            List destination = web.Lists.GetByTitle(destinationListName);
            context.Load(source);
            context.Load(destination);
            context.Load(web);
            context.ExecuteQuery();

            FileCollection rootFiles = source.RootFolder.Files;

            context.Load(rootFiles);
            context.ExecuteQuery();

            foreach (Microsoft.SharePoint.Client.File file in rootFiles)
            {
                FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, file.ServerRelativeUrl);
                string filePath = host + file.ServerRelativeUrl;
                System.IO.Stream fileStream = fileInfo.Stream;
                FileCreationInformation createFile = new FileCreationInformation();
                byte[] bufferByte = new byte[1024 * 100];
                System.IO.MemoryStream memory = new System.IO.MemoryStream();
                int len = 0;
                while ((len = fileStream.Read(bufferByte, 0, bufferByte.Length)) > 0)
                {
                    memory.Write(bufferByte, 0, len);
                }
                byte[] bytes = memory.GetBuffer();

                createFile.Content = bytes;
                createFile.Url = siteUrl + "/" + destinationListName + "/" + file.Name;
                createFile.Overwrite = true;
                Microsoft.SharePoint.Client.File newFile = destination.RootFolder.Files.Add(createFile);
                newFile.ListItemAllFields.Update();
                context.ExecuteQuery();

                ListItem item = file.ListItemAllFields;
                context.Load(item);
                item.DeleteObject();
                context.ExecuteQuery();
            }

            //FolderCollection subFolders = source.RootFolder.Folders;
            //foreach(Folder folder in subFolders)
            //{

            //}

        }
        #endregion

        #region Move 某个site collection 的 Doc 中的某个文件到另一个site collection 的 Doc中(在同一个Web Application下)
        /// <summary>
        /// Move 某个site collection 的 Doc 中的某个文件到另一个site collection 的 Doc中
        /// </summary>
        /// <param name="sourceContext"></param>
        /// <param name="destinationContext"></param>
        /// <param name="sourceListName">sourceList</param>
        /// <param name="destinationListName">destinationList</param>
        /// <param name="fileName">/folder/test.txt</param>
        public static void MoveDocFromOneListToAnother(ClientContext sourceContext, ClientContext destinationContext, string sourceListName, string destinationListName, string fileRelativePath)
        {
            Web sourceWeb = sourceContext.Web;
            Web destinationWeb = destinationContext.Web;
            sourceContext.Load(sourceWeb);
            destinationContext.Load(destinationWeb);
            sourceContext.ExecuteQuery();
            destinationContext.ExecuteQuery();

            string sourceSiteUrl = sourceWeb.Url;

            string host = null;
            if (sourceSiteUrl.Split('/').Length > 3)
            {
                string[] strArr = sourceSiteUrl.Split('/');
                for (int x = 0; x < 3; x++)
                {
                    if (x != 2)
                    {
                        host += strArr[x] + "/";
                    }
                    else
                    {
                        host += strArr[x];
                    }
                }
            }
            else
            {
                host = sourceSiteUrl;
            }

            List source = sourceWeb.Lists.GetByTitle(sourceListName);
            List destination = destinationWeb.Lists.GetByTitle(destinationListName);
            sourceContext.Load(source);
            destinationContext.Load(destination);
            sourceContext.Load(sourceWeb);
            sourceContext.ExecuteQuery();
            destinationContext.ExecuteQuery();

            FileCollection files = source.RootFolder.Files;
            Microsoft.SharePoint.Client.File file = files.GetByUrl(sourceSiteUrl + "/" + sourceListName + fileRelativePath);
            sourceContext.Load(file);
            sourceContext.ExecuteQuery();

            FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(sourceContext, file.ServerRelativeUrl);
            string filePath = host + file.ServerRelativeUrl;
            System.IO.Stream fileStream = fileInfo.Stream;
            FileCreationInformation createFile = new FileCreationInformation();
            byte[] bufferByte = new byte[1024 * 100];
            System.IO.MemoryStream memory = new System.IO.MemoryStream();
            int len = 0;
            while ((len = fileStream.Read(bufferByte, 0, bufferByte.Length)) > 0)
            {
                memory.Write(bufferByte, 0, len);
            }
            byte[] bytes = memory.GetBuffer();

            createFile.Content = bytes;
            createFile.Url = sourceSiteUrl + "/" + destinationListName + "/" + file.Name;
            createFile.Overwrite = true;
            Microsoft.SharePoint.Client.File newFile = destination.RootFolder.Files.Add(createFile);
            newFile.ListItemAllFields.Update();
            destinationContext.ExecuteQuery();

            ListItem item = file.ListItemAllFields;
            sourceContext.Load(item);
            item.DeleteObject();
            sourceContext.ExecuteQuery();
        }
        #endregion

        #region 从Document Library下载文件
        /// <summary>
        /// 从Document Library下载文件
        /// </summary>
        /// <param name="siteUrl">http://sp/sites/DevSite</param>
        /// <param name="ListName">MyDocumentLibrary</param>
        /// <param name="fileName">test.txt</param>
        /// <param name="filePath">C:\\</param>
        public static void downloadFile(string siteUrl, string ListName, string fileName, string filePath)
        {
            siteUrl = siteUrl.EndsWith("/") ? siteUrl.Substring(0, siteUrl.Length - 1) : siteUrl;
            ClientContext context = new ClientContext(siteUrl);
            Web web = context.Site.RootWeb;

            List source = web.Lists.GetByTitle(ListName);
            context.Load(source);
            context.ExecuteQuery();

            FileCollection files = source.RootFolder.Files;
            Microsoft.SharePoint.Client.File file = files.GetByUrl(siteUrl + "/" + ListName + "/" + fileName);
            context.Load(file);
            context.ExecuteQuery();

            FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, file.ServerRelativeUrl);
            Stream fileInputStream = fileInfo.Stream;
            FileStream fileOutputStream = new FileStream(filePath + fileName, FileMode.OpenOrCreate | FileMode.Append, FileAccess.Write, FileShare.None);
            byte[] bufferByte = new byte[1024 * 100];

            int len = 0;
            while ((len = fileInputStream.Read(bufferByte, 0, bufferByte.Length)) > 0)
            {
                fileOutputStream.Write(bufferByte, 0, len);
                fileOutputStream.Flush(true);
            }
            fileOutputStream.Close();
        }
        #endregion

        #region 下载Document Library中的所有文件到本地
        /// <summary>
        /// 下载Document Library中的所有文件到本地
        /// </summary>
        /// <param name="context"></param>
        /// <param name="docLibName">MyDocumentLibrary</param>
        /// <param name="path">C:\\folder\\</param>
        public static void DownloadAllFilesFromDocLib(ClientContext context, string docLibName, string path)
        {
            //init
            if (!path.EndsWith("\\"))
            {
                path = path + "\\";
            }
            Web web = context.Site.RootWeb;

            List doclib = web.Lists.GetByTitle(docLibName);

            context.Load(doclib);

            context.Load(web);
            context.ExecuteQuery();

            FileCollection filesInRootFolder = doclib.RootFolder.Files;
            FolderCollection subfolders = doclib.RootFolder.Folders;
            context.Load(filesInRootFolder);
            context.Load(subfolders);
            context.ExecuteQuery();

            //download files from root folders
            foreach (Microsoft.SharePoint.Client.File file in filesInRootFolder)
            {
                FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, file.ServerRelativeUrl);
                System.IO.Stream fileOutputStream = fileInfo.Stream;
                System.IO.Stream fileInputputStream = new FileStream(path + file.Name, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                byte[] bufferByte = new byte[1024 * 100];

                int len = 0;
                while ((len = fileOutputStream.Read(bufferByte, 0, bufferByte.Length)) > 0)
                {
                    fileInputputStream.Write(bufferByte, 0, len);
                    fileInputputStream.Flush();
                }
                fileInputputStream.Close();
                fileOutputStream.Close();

            }

            //download all files from sub folders
            foreach (Microsoft.SharePoint.Client.Folder folder in subfolders)
            {
                //Remove the default folder "Forms"
                if (folder.Name == "Forms")
                {
                    continue;
                }
                //create folder in local disk
                Directory.CreateDirectory(path + folder.Name);
                context.Load(folder.Files);
                context.ExecuteQuery();

                foreach (Microsoft.SharePoint.Client.File file in folder.Files)
                {
                    FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, file.ServerRelativeUrl);
                    System.IO.Stream fileOutputStream = fileInfo.Stream;
                    System.IO.Stream fileInputputStream = new FileStream(path + folder.Name + "\\" + file.Name, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                    byte[] bufferByte = new byte[1024 * 100];

                    int len = 0;
                    while ((len = fileOutputStream.Read(bufferByte, 0, bufferByte.Length)) > 0)
                    {
                        fileInputputStream.Write(bufferByte, 0, len);
                        fileInputputStream.Flush();
                    }
                    fileInputputStream.Close();
                    fileOutputStream.Close();
                }
            }
        }
        #endregion       

        #region 使用REST API来下载document library中的文件
        /// <summary>
        /// 使用REST API来下载document library中的文件
        /// REST URL example:  //https://xxxx.sharepoint.com/sites/LeeLiuDevSite/_api/web/GetFileByServerRelativeUrl('/sites/LeeLiuDevSite/MyCocumentLib/test.docx')/$value
        /// </summary>
        /// <param name="webUrl">https://xxxxx/sites/LeeLiuDevSite</param>
        /// <param name="credentials"></param>
        /// <param name="documentLibName">MyDocumentLibrary</param>
        /// <param name="fileName">test.docx</param>
        /// <param name="path">C:\\</param>
        public static void DownloadFileViaRestAPI(string webUrl, ICredentials credentials, string documentLibName, string fileName, string path)
        {
            webUrl = webUrl.EndsWith("/") ? webUrl.Substring(0, webUrl.Length - 1) : webUrl;
            string webRelativeUrl = null;
            if (webUrl.Split('/').Length > 3)
            {
                webRelativeUrl = "/" + webUrl.Split(new char[] { '/' }, 4)[3];
            }
            else
            {
                webRelativeUrl = "";
            }

            using (WebClient client = new WebClient())
            {
                client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
                client.Credentials = credentials;
                Uri endpointUri = new Uri(webUrl + "/_api/web/GetFileByServerRelativeUrl('" + webRelativeUrl + "/" + documentLibName + "/" + fileName + "')/$value");
                byte[] data = client.DownloadData(endpointUri);
                FileStream outputStream = new FileStream(path + fileName, FileMode.OpenOrCreate | FileMode.Append, FileAccess.Write, FileShare.None);
                outputStream.Write(data, 0, data.Length);
                outputStream.Flush(true);
                outputStream.Close();
            }
        }
        #endregion

        #region 上传文件到document library
        /// <summary>
        /// 上传文件到document library
        /// </summary>
        /// <param name="siteUrl">http://sp/sites/DevSite</param>
        /// <param name="filePath">C:\\</param>
        /// <param name="fileName">hello2.txt</param>
        /// <param name="docLibName">MyDocLib</param>
        public static void uploadFile(string siteUrl, string filePath, string fileName, string docLibName)
        {
            siteUrl = siteUrl.EndsWith("/") ? siteUrl.Substring(0, siteUrl.Length - 1) : siteUrl;
            ClientContext context = new ClientContext(siteUrl);
            List docLib = context.Web.Lists.GetByTitle(docLibName);
            context.Load(docLib);
            context.ExecuteQuery();

            Byte[] bytes = System.IO.File.ReadAllBytes(filePath + fileName);

            FileCreationInformation createFile = new FileCreationInformation();

            createFile.Content = bytes;
            createFile.Url = siteUrl + "/" + docLibName + "/" + fileName;
            createFile.Overwrite = true;
            Microsoft.SharePoint.Client.File newFile = docLib.RootFolder.Files.Add(createFile);
            newFile.ListItemAllFields.Update();
            context.ExecuteQuery();
        }

        /// <summary>
        /// upload file to Document Library
        /// </summary>
        /// <param name="context"></param>
        /// <param name="documentLibraryName">MyDocLib</param>
        /// <param name="filePath">C:\\</param>
        /// <param name="fileName">hello2.txt</param>
        public static void uploadFile(ClientContext context, string documentLibraryName, string filePath, string fileName)
        {

            string siteURL = context.Url.EndsWith("/") ? context.Url.Substring(0, context.Url.Length - 1) : context.Url;

            List list = context.Web.Lists.GetByTitle(documentLibraryName);
            context.Load(list);
            context.ExecuteQuery();

            FileStream fileStream = new FileStream(filePath, FileMode.Open);

            FileCreationInformation newFileInfo = new FileCreationInformation()
            {
                ContentStream = fileStream,
                Url = siteURL + "/" + documentLibraryName + "/" + fileName,
                Overwrite = true
            };

            Microsoft.SharePoint.Client.File file = list.RootFolder.Files.Add(newFileInfo);
            context.Load(file);
            context.ExecuteQuery();
        }
        #endregion

        #region 给item添加attachment
        /// <summary>
        /// 给item添加attachment
        /// </summary>
        /// <param name="siteURL">http://sp:5000</param>
        /// <param name="listName">list1</param>
        /// <param name="itemID">1</param>
        /// <param name="filePath">C:\Users\spsvc\Desktop\test3.docx</param>
        public static void addAttachmentToListItem(ClientContext Context, string listName, int itemID, string filePath)
        {
            var list = Context.Web.Lists.GetByTitle(listName);
            Context.Load(list);
            Context.ExecuteQuery();

            ListItem item = list.GetItemById(itemID);
            Context.Load(item);
            Context.ExecuteQuery();
            if (item != null)
            {
                FileStream fileStream = new FileStream(filePath, FileMode.Open);
                AttachmentCreationInformation attInfo = new AttachmentCreationInformation();
                attInfo.ContentStream = fileStream;
                attInfo.FileName = fileStream.Name;
                Attachment attachment = item.AttachmentFiles.Add(attInfo);
                Context.Load(attachment);
                Context.ExecuteQuery();
                fileStream.Close();
            }
        }
        #endregion

        #region 创建一个list
        /// <summary>
        /// 创建一个list
        /// </summary>
        /// <param name="context"></param>
        /// <param name="name"></param>
        /// <param name="description"></param>
        /// <param name="templateType"></param>
        public static void createList(ClientContext context, String name, string description, ListTemplateType templateType)
        {
            ListCreationInformation lci = new ListCreationInformation();
            lci.Description = description;
            lci.Title = name;
            lci.TemplateType = (int)templateType;
            List newLib = context.Web.Lists.Add(lci);
            context.Load(newLib);
            context.ExecuteQuery();
        }
        #endregion

        #region 在Pages这个列表中创建一个aspx页
        /// <summary>
        /// 在Pages这个列表中创建一个aspx页
        /// </summary>
        /// <param name="context"></param>
        /// <param name="pageName"></param>
        /// <param name="templateRedirectionPageMarkup">aspx页面的具体内容</param>
        public static void createWiKiPage(ClientContext context, string pageName, string templateRedirectionPageMarkup)
        {
            //string templateRedirectionPageMarkup = System.IO.File.ReadAllText("C:\\Users\\spsvc\\Desktop\\page.txt");        

            List wikiPages = context.Web.Lists.GetByTitle("Pages");

            context.Load(wikiPages);

            context.ExecuteQuery();

            FileCreationInformation file = new FileCreationInformation
            {
                Url = pageName,
                Content = Encoding.UTF8.GetBytes(templateRedirectionPageMarkup),
                Overwrite = true
            };

            Microsoft.SharePoint.Client.File wikiFile = wikiPages.RootFolder.Files.Add(file);

            context.Load(wikiFile);

            context.ExecuteQuery();

            ListItem wikiPageItem = wikiFile.ListItemAllFields;

            wikiPageItem["PublishingPageContent"] = "<div>hello world</div>";

            wikiPageItem["PublishingPageLayout"] = "/_catalogs/masterpage/EnterpriseWiki.aspx, Basic Page";

            wikiPageItem.Update();

            context.ExecuteQuery();


        }
        #endregion

        #region 给页面添加web part
        /// <summary>
        /// 给页面添加web part
        /// </summary>
        /// <param name="context"></param>
        /// <param name="pageUrl">/{web site}/.../xxx.aspx</param>
        /// <param name="webPartXml">
        /// full xml code of web part.
        /// About how to export web part xml, refer to: https://chuvash.eu/2014/09/19/export-any-web-part-from-a-sharepoint-page/
        /// </param>
        /// <param name="chekInMessage"></param>
        /// <param name="web"></param>
        /// <param name="location">the location of web part. For example: Bottom</param>
        public static void addWebPartToPage(ClientContext context, string pageUrl, String webPartXml, string chekInMessage, string location, Web web)
        {
            Microsoft.SharePoint.Client.File page = context.Web.GetFileByServerRelativeUrl(pageUrl);
            context.Load(page);
            context.ExecuteQuery();
            LimitedWebPartManager webPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared);
            WebPartDefinition importedWebPart = webPartManager.ImportWebPart(webPartXml);
            WebPartDefinition webPart = webPartManager.AddWebPart(importedWebPart.WebPart, location, 0);
            context.Load(webPart);
            context.ExecuteQuery();
            page.CheckIn(chekInMessage, CheckinType.MinorCheckIn);
        }
        #endregion

        #region 根据Title删除页面里的某个web part
        /// <summary>
        /// 根据Title删除页面里的某个web part
        /// </summary>
        /// <param name="context"></param>
        /// <param name="pageUrl">/{web site}/.../xxx.aspx</param>
        /// <param name="webPartTitle">The Title of web part</param>
        public static void removeWebPartFromPage(ClientContext context, string pageUrl, string webPartTitle)
        {
            Microsoft.SharePoint.Client.File file = context.Web.GetFileByServerRelativeUrl(pageUrl);
            LimitedWebPartManager wpm = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
            context.Load(wpm.WebParts,
            wps => wps.Include(
            wp => wp.WebPart.Title));
            context.ExecuteQuery();
            foreach (WebPartDefinition wpd in wpm.WebParts)
            {
                WebPart wp = wpd.WebPart;
                if (wp.Title == webPartTitle)
                {
                    wpd.DeleteWebPart();
                    context.ExecuteQuery();
                }
            }
        }
        #endregion

        #region 从一个自定义的list Template中创建一个list
        /// <summary>
        /// 从一个自定义的list Template中创建一个list  注意: 需要16 online版本的dll文件  下载链接：https://www.microsoft.com/en-us/download/details.aspx?id=42038
        /// </summary>
        /// <param name="clientContext"></param>
        /// <param name="templateName"></param>
        /// <param name="listName"></param>
        /// <param name="listDescription"></param>
        public static List createListFromCustomTemplate(ClientContext clientContext, string templateName, string listName, string listDescription)
        {
            //create a ListTemplateCollection object which contain the custom list template
            ListTemplateCollection listTemplateCollection = clientContext.Site.GetCustomListTemplates(clientContext.Web);

            //load and execute
            clientContext.Load(listTemplateCollection);
            clientContext.ExecuteQuery();

            //claim a ListTemplate object
            ListTemplate listTemplate = null;

            //set a flag to adjust whether the template you want is exist
            bool flag = false;

            //achieve the template which you want by select the template name
            foreach (ListTemplate Template in listTemplateCollection)
            {
                if (Template.Name.Equals(templateName))
                {
                    listTemplate = Template;
                    flag = true;
                    break;
                }
            }

            //if there is a template you want
            if (flag)
            {
                //create ListCreationInformation object which contains the infomation that belongs to the list you want to create
                ListCreationInformation listCreationInfo = new ListCreationInformation();

                //set Description
                listCreationInfo.Description = listDescription;

                //set title
                listCreationInfo.Title = listName;

                //set the template
                listCreationInfo.ListTemplate = listTemplate;

                //add to list collection
                List newLib = clientContext.Web.Lists.Add(listCreationInfo);

                //load and execute
                clientContext.Load(newLib);
                clientContext.ExecuteQuery();

                return newLib;
            }

            //if there is not a template you want
            else
            {
                return null;
            }
        }
        #endregion

        #region 上传文件到Document Library/List Root Folder
        /// <summary>
        /// 上传文件到Document Library/List Root Folder
        /// </summary>
        /// <param name="context"></param>
        /// <param name="docName"></param>
        /// <param name="filePath"></param>
        /// <param name="fileName"></param>
        public static void uploadFileToDocLib(ClientContext context, string docName, string filePath, string fileName)
        {

            string siteURL = context.Url.EndsWith("/") ? context.Url.Substring(0, context.Url.Length - 1) : context.Url;

            List list = context.Web.Lists.GetByTitle(docName);
            context.Load(list);
            context.ExecuteQuery();

            FileStream fileStream = new FileStream(filePath, FileMode.Open);

            FileCreationInformation newFileInfo = new FileCreationInformation()
            {
                ContentStream = fileStream,
                Url = siteURL + "/" + docName + "/" + fileName,
                Overwrite = true
            };

            Microsoft.SharePoint.Client.File file = list.RootFolder.Files.Add(newFileInfo);
            context.Load(file);
            context.ExecuteQuery();
        }
        #endregion

        #region 激活/关闭Feature
        /// <summary>
        /// 激活Feature
        /// </summary>
        /// <param name="context"></param>
        /// <param name="featureId"></param>
        /// <param name="force">true</param>
        /// <param name="featdefScope">
        ///        在CSOM API v16的版本中
        ///        必须是FeatureDefinitionScope.Site, FeatureDefinitionScope.Farm或者FeatureDefinitionScope.None
        ///        因为CSOM不支持web scope的feature，所以要想激活web scope，值需要为FeatureDefinitionScope.None
        /// </param>
        public static void ActivateFeature(ClientContext context, Guid featureId, bool force, FeatureDefinitionScope featdefScope)
        {
            FeatureCollection features = context.Web.Features;
            context.Load(features);
            context.ExecuteQuery();

            features.Add(featureId, force, featdefScope);
            context.ExecuteQuery();
        }

        /// <summary>
        /// 关闭某个Web的Feature
        /// </summary>
        /// <param name="context"></param>
        /// <param name="featureId"></param>
        /// <param name="force"></param>
        public static void DeactivateWebFeature(ClientContext context, Guid featureId, bool force)
        {
            FeatureCollection features = context.Web.Features;
            context.Load(features);
            context.ExecuteQuery();

            features.Remove(featureId, force);
            context.ExecuteQuery();
        }

        /// <summary>
        /// 关闭某个Site的Feature
        /// </summary>
        /// <param name="context"></param>
        /// <param name="featureId"></param>
        /// <param name="force"></param>
        public static void DeactivateSiteFeature(ClientContext context, Guid featureId, bool force)
        {
            FeatureCollection features = context.Site.Features;
            context.Load(features);
            context.ExecuteQuery();

            features.Remove(featureId, force);
            context.ExecuteQuery();
        }
        #endregion      

        #region 获取某个folder中的所有Item
        /// <summary>
        /// 获取某个folder中的所有Item
        /// </summary>
        /// <param name="folderServerRelativeUrl"></param>
        /// <param name="list"></param>
        /// <param name="clientContext"></param>
        /// <returns></returns>
        public List<ListItem> GetFolderItems(string folderServerRelativeUrl, List list, ClientContext clientContext)
        {
            try
            {
                List<ListItem> result = new List<ListItem>();
                var query = new CamlQuery();

                query.FolderServerRelativeUrl = folderServerRelativeUrl;

                query.ViewXml = "<View Scope=\"RecursiveAll\"> " +
                    "<Query>" +
                    "<Where>" +
                                "<Eq>" +
                                    "<FieldRef Name=\"FileDirRef\" />" +
                                    "<Value Type=\"Text\">" + folderServerRelativeUrl + "</Value>" +
                                 "</Eq>" +
                    "</Where>" +
                    "</Query>" +
                    "</View>";

                ListItemCollection folderItems = list.GetItems(query);
                clientContext.Load(folderItems);
                clientContext.ExecuteQuery();

                foreach (ListItem item in folderItems)
                {
                    // item[ "..." ];
                    result.Add(item);
                }

                return result;
            }
            catch (Exception)
            {
                return null;
            }
        }
        #endregion

        /*
         * 下面是一个demo 
         */

        /// <summary>
        /// 在Folder中创建Item
        /// </summary>
        /// <param name="context"></param>
        /// <param name="RelativeFolderUrl"></param>
        /// <param name="listName"></param>
        public static void createItemInFolder(ClientContext context, string RelativeFolderUrl, string listName)
        {
            List list = context.Web.Lists.GetByTitle(listName);
            context.Load(list);
            context.ExecuteQuery();
            ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
            itemCreateInfo.FolderUrl = RelativeFolderUrl;

            ListItem listItem = list.AddItem(itemCreateInfo);
            listItem["Title"] = "wakaka";
            listItem.Update();
            context.Load(listItem);
            context.ExecuteQuery();
        }




    }
}
